﻿using Microsoft.AspNetCore.Http;
using NPOI.HSSF.UserModel;
using NPOI.SS.Formula.Functions;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using Org.BouncyCastle.Asn1.X509;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace ExcelHelperSpace
{
    public class ExcelMapper : IExcelMapper
    {
        static readonly TypeObject DefaultTypeObject = new();
        public ITypeObjectFactory TypeObjectFactory { get; set; } = DefaultTypeObject;

        IWorkbook Workbook { get; set; }
        public string defaultPath { get; set; } = Directory.GetCurrentDirectory();

        public IFormFile FormFile { get; set; }

        public ExcelMapper()
        {

        }

        public ExcelMapper(IFormFile file)
        {
            FormFile = file;
            using (var writer = new MemoryStream())
            {
                FormFile.CopyTo(writer);
                Workbook = WorkbookFactory.Create(writer);
            }
        }


        /// <summary>
        /// 从第一行索引开始
        /// </summary>
        public int firstRowNumber = 0;
        /// <summary>
        /// 从第一列索引开始
        /// </summary>
        public int firstCellNumber = 0;
        /// <summary>
        /// 从第一个sheet开始
        /// </summary>
        public int sheetIndex = 0;

        /// <summary>
        /// 开始获取数据的行索引
        /// </summary>
        public int startGetRowNumber = 1;

        /// <summary>
        /// .xlsx or .xls
        /// </summary>
        public bool xlsx = true;

        /// <summary>
        /// 初始化参数
        /// </summary>
        /// <param name="excelClass"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void ExcelInit(ExcelClass excelClass)
        {
            firstRowNumber = excelClass.firstRowNumber;
            firstCellNumber = excelClass.firstCellNumber;
        }

        public IEnumerable<T> ExcelToList<T>(string path)
        {
            if (File.Exists(path))
            {
                using (var filestream = new FileStream(path, FileMode.Open))
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        filestream.CopyTo(ms);
                        //执行转换
                        return ExcelToList<T>(ms);
                    }
                }
            }
            else
            {
                return null;
            }
        }

        public IEnumerable<T> ExcelToList<T>(IFormFile file)
        {
            return ExcelToList<T>(sheetIndex);
        }

        public IEnumerable<T> ExcelToList<T>(MemoryStream writer)
        {
            Workbook = WorkbookFactory.Create(writer);
            return ExcelToList<T>(sheetIndex);
        }

        public IEnumerable<T> ExcelToList<T>(int sheetindex = 0)
        {
            var sheet = Workbook.GetSheetAt(sheetindex);
            return Fetch<T>(sheet);
        }

        public IEnumerable<T> Fetch<T>(ISheet sheet)
        {
            return Fetch(sheet, typeof(T)).OfType<T>();
        }

        /// <summary>
        /// 将excel转换成对象
        /// </summary>
        /// <param name="sheet"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        IEnumerable Fetch(ISheet sheet, Type type)
        {
            var RowNumber = firstRowNumber;

            //匹配excel的列索引和对象的字段

            var firstRow = sheet.GetRow(firstRowNumber);
            //如果excel是空表直接结束迭代
            if (firstRow == null)
            {
                yield break;
            }
            var firstCell = Enumerable.Range(0, firstRow.LastCellNum).Select(i => firstRow.GetCell(i, MissingCellPolicy.CREATE_NULL_AS_BLANK));
            var firstCellAndDes = SetRowIndexDic(type, firstCell);

            for (int i = startGetRowNumber; i <= sheet.LastRowNum - 1; i++)
            {
                var indexrow = sheet.GetRow(i);

                //获取指定范围的整数序列
                var cells = Enumerable.Range(0, indexrow.LastCellNum).Select(i => indexrow.GetCell(i, MissingCellPolicy.CREATE_NULL_AS_BLANK));
                var indexRowCells = cells.Where(c => !true || !string.IsNullOrWhiteSpace(c.ToString()));
                //赋值对象
                var o = TypeObjectFactory.Create(type, indexRowCells, firstCellAndDes);

                yield return o;
            }
        }



        ///// <summary>
        ///// List To Excel
        ///// </summary>
        ///// <typeparam name="T"></typeparam>
        ///// <param name="list"></param>
        ///// <param name="sheetName"></param>
        ///// <returns></returns>
        ///// <exception cref="NotImplementedException"></exception>
        //public byte[] GListToExcel<T>(Stream stream, IEnumerable<T> list, string sheetName = "Sheet1", bool xlsx = true)
        //{
        //    Workbook ??= xlsx ? (IWorkbook)new XSSFWorkbook() : (IWorkbook)new HSSFWorkbook();
        //    var sheet = Workbook.GetSheet(sheetName);
        //    sheet ??= Workbook.CreateSheet(sheetName);

        //}

        /// <summary>
        /// 列赋值
        /// </summary>
        public void SetColumns(ISheet sheet, IEnumerable<T> list)
        {
            var first = list.FirstOrDefault();
            var firstColnum = new Dictionary<int, StructStats>();
            if (first == null)
            {
                var t = first.GetType();
                firstColnum = GetRowIndexDic(t);
            }

            var Firstrow = sheet.CreateRow(firstRowNumber);

            for (int i = 0; i <= firstColnum.Count() - 1; i++)
            {
                var Toprow = Firstrow.CreateCell(0);
                Toprow.SetCellValue(firstColnum[i].Des);


            }

            for (int i = firstRowNumber; i <= list.Count() + firstRowNumber - 1; i++)
            {

            }

        }


        /// <summary>
        /// 获取第一行数据并绑定对象字段
        /// </summary>
        /// <param name="firstCells"></param>
        /// <returns></returns>
        private Dictionary<string, int> SetRowIndexDic(Type t, IEnumerable<ICell> firstCells)
        {
            var dic = new Dictionary<string, int>();
            foreach (var prop in t.GetProperties())
            {
                var objs = prop.GetCustomAttributes(typeof(SlwDes), true);
                var Des = prop.Name;
                if (objs.Length > 0 && ((SlwDes)objs[0]).Des != null)
                {
                    //有列字段描述
                    Des = ((SlwDes)objs[0]).Des;
                }

                foreach (var c in firstCells)
                {
                    if (c.CellType == CellType.String)
                    {
                        if (Des == c.StringCellValue)
                        {
                            dic[Des] = c.ColumnIndex;
                            break;
                        }
                    }
                    if (c.CellType == CellType.Numeric)
                    {
                        if (Des == c.NumericCellValue.ToString())
                        {
                            dic[Des] = c.ColumnIndex;
                            break;
                        }
                    }
                    if (c.CellType == CellType.Unknown)
                    {
                        break;
                    }
                    if (c.CellType == CellType.Formula)
                    {
                        break;
                    }
                    if (c.CellType == CellType.Blank)
                    {
                        break;
                    }
                    if (c.CellType == CellType.Boolean)
                    {
                        break;
                    }
                    if (c.CellType == CellType.Error)
                    {
                        break;
                    }
                }
            }
            return dic;
        }

        /// <summary>
        /// 获取第一组集合信息
        /// </summary>
        /// <returns></returns>
        private Dictionary<int, StructStats> GetRowIndexDic(Type t)
        {
            var colnumsDic = new Dictionary<int, StructStats>();

            var propIndex = 0;
            foreach (var prop in t.GetProperties())
            {
                var objs = prop.GetCustomAttributes(typeof(SlwDes), true);
                var Des = prop.Name;
                if (objs.Length > 0 && ((SlwDes)objs[0]).Des != null)
                {
                    //有列字段描述
                    Des = ((SlwDes)objs[0]).Des;
                }

                colnumsDic[propIndex] = new StructStats
                {
                    Des = Des,
                    Name = prop.Name,
                    SystemName = prop.PropertyType.Name,
                };

                propIndex++;
            }

            return colnumsDic;
        }


        public class StructStats
        {
            /// <summary>
            /// 字段描述
            /// </summary>
            public string Des { get; set; }
            /// <summary>
            /// 字段属性
            /// </summary>
            public string Name { get; set; }

            /// <summary>
            /// 字段类型
            /// </summary>
            public string SystemName { get; set; }
        }
    }
}
